#!/usr/bin/evn python
# -*- coding: utf-8 -*-
"""
description: please input using description
author: justbk
date: 2021/7/5
modify_records:
    - 2021/7/5 justbk create this file
"""
import re
from datetime import datetime

from singleton import Singleton
from record import TimestampDesc


class LogAnalyzeLineChain:
    TAG_NEWORDER = "NEW_ORDER"
    TAG_DELIVERY_BG = "DELIVERY_BG"
    TAG_DELIVERY = "DELIVERY"
    TAG_PAYMENT = "PAYMENT"
    TAG_ORDER_STATUS = "ORDER_STATUS"
    TAG_STOCK_LEVEL = "STOCK_LEVEL"
    TAG_NONE = "NONE"
    TAG_DONE = "DONE"
    PATTERN = re.compile(
        "(\d{2}):(\d{2}):(\d{2}),(\d{3})\s+\[\s*(\S+)\].+====\s+(\w+)\s+(\w+)\s+====\s+\S+\s+(\d+),(\d+)\s+===")

    def __init__(self, tag, next_chain=None, calc=None):
        self.tag = tag
        self.next_chain = next_chain
        self.calc = calc

    def match(self, line: str):
        return self.tag in line and '====' in line

    def analyze(self, line):
        if self.calc is not None:
            self.calc.report(self.get_info_from_line(line))

    @classmethod
    def get_info_from_line(cls, line):
        hour, minute, second, millsecond, thread_name, tag, io_desc, warehouse, distinct\
            = cls.PATTERN.match(line).groups()
        desc = TimestampDesc()
        desc.tag = tag
        desc.distinct = distinct
        desc.warehouse = warehouse
        desc.thread_name = thread_name
        desc.is_input = True if io_desc == "INPUT" else False

        date = datetime.now().date()
        year, month, day = date.year, date.month, date.day
        tmp_begin_time = datetime(year, month=month, day=day, hour=int(hour), minute=int(minute), second=int(second), microsecond=int(millsecond) * 1000).timestamp()
        desc.begin_time = tmp_begin_time * 1000
        return desc

    def doit(self, line):
        if self.match(line):
            self.analyze(line)
            return
        if self.next_chain is not None:
            self.next_chain.doit(line)

    @classmethod
    def get_all_tag(cls):
        results = []
        for attr in dir(LogAnalyzeLineChain):
            if attr.startswith("TAG_"):
                results.append(getattr(LogAnalyzeLineChain, attr))
        return results

    @classmethod
    def generate_chains(cls, calc):
        next_chain = None
        for attr in cls.get_all_tag():
            cur_chain = cls(attr, next_chain, calc)
            next_chain = cur_chain
        return next_chain


class ArrayTimeStampDesc(Singleton):
    def __init__(self, *args, **kwargs):
        self.map_result = {}
        for attr in LogAnalyzeLineChain.get_all_tag():
            self.map_result[attr] = []

    def add(self, report):
        self.map_result[report.tag].append(report)

    def output(self):
        titles = ['name', 'first', 'last', 'avg', 'max', 'min', 'count']
        format_pattern = '{0:>15}  {1:>10} {2:>10} {3:>12} {4:>10} {5:>10} {6:>10}'
        print(format_pattern.format(titles[0], titles[1], titles[2], titles[3], titles[4], titles[5], titles[6]))
        format_pattern_value = '{0:>15}  {1:>10} {2:>10} {3:>12f} {4:>10} {5:>10} {6:>10}'
        for key, values in self.map_result.items():
            if len(values) == 0:
                continue
            analyzes = self.record_analyze(values)
            output_desc = format_pattern_value.format(key, analyzes[0], analyzes[1], analyzes[2], analyzes[3], analyzes[4], len(values))
            print(output_desc)

    @classmethod
    def record_analyze(cls, records):
        perferances = list(map(lambda x: x.get_performance(), records))
        first = perferances[0]
        last = perferances[-1]
        avg = sum(perferances) / len(perferances)
        min_v = min(perferances)
        max_v = max(perferances)
        return first, last, avg, max_v, min_v


class TimestampCalc:
    def __init__(self):
        self.map_timestamp_desc = {}

    def report(self, record):
        key = record.unique_key()
        if key in self.map_timestamp_desc:
            if record.is_input:
                raise ValueError("order not correct!")
            record.end_time = record.begin_time
            record.begin_time = self.map_timestamp_desc[key].begin_time
            self.map_timestamp_desc.pop(key)
            ArrayTimeStampDesc().add(record)
        else:
            if not record.is_input:
                raise ValueError("order not corrent when is not input")
            self.map_timestamp_desc[key] = record